//
//  UITextView+LinkTextView.swift
//  SwiftCode
//
//  Created by 于虎拴 on 2022/8/5.
//

import Foundation
import UIKit

open class LinkTextView: UITextView {
  public struct Link {
    let text: String
    let attrs: [NSAttributedString.Key : Any]
    let link: String
    let action: ((URL) -> Void)?
    
    public init(text: String, attrs: [NSAttributedString.Key : Any], link: String, action: ((URL) -> Void)? = nil) {
      self.text = text
      self.attrs = attrs
      self.link = link
      self.action = action
    }
  }
  
  private var links: [Link] = []
  private var defaultAttrs: [NSAttributedString.Key : Any] = [
    .font: UIFont.systemFont(ofSize: 17),
    .foregroundColor: UIColor.black
  ]
  
  public init(_ attrs: [NSAttributedString.Key : Any] = [:]) {
    super.init(frame: .zero, textContainer: nil)
    
    defaultAttrs.merge(attrs, uniquingKeysWith: {$1})
    
    isEditable = false
    layoutManager.allowsNonContiguousLayout = false
    textContainerInset = .zero
    textContainer.lineFragmentPadding = 0
    isScrollEnabled = false
    linkTextAttributes = [:]
    delegate = self
  }
  
  required public init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  public func set(text: String, links: [Link]) {
    self.links = links
    
    let attrString: NSMutableAttributedString = NSMutableAttributedString(string: text, attributes: defaultAttrs)
    
    links.forEach { link in
      if let range = text.range(of: link.text) {
        var linkAttr: [NSAttributedString.Key : Any] = [
          .link: link.link,
          .foregroundColor: UIColor.blue
        ]
        linkAttr.merge(link.attrs, uniquingKeysWith: {$1})
        attrString.addAttributes(linkAttr, range: NSRange(range, in: text))
      }
    }
    
    attributedText = attrString
  }
  
  open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if #available(iOS 12, *) {
      switch gestureRecognizer.name {
      case "UITextInteractionNameSingleTap":
        return true
      case "UITextInteractionNameLinkTap":
        return true
      case "UITextInteractionNameDoubleTap":
        return false
      case "UITextInteractionNameTapAndAHalf":
        return false
      case "_UIKeyboardTextSelectionGestureForcePress":
        return false
      case "UITextInteractionNameInteractiveLoupe":
        return false
      default:
        return super.gestureRecognizerShouldBegin(gestureRecognizer)
      }
    }
    return super.gestureRecognizerShouldBegin(gestureRecognizer)
  }
}

extension LinkTextView: UITextViewDelegate{
  public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
    if let link = links.first(where: { $0.link == URL.absoluteString }),
       let action = link.action{
      action(URL)
      return false
    }
    return true
  }
}
